package com.gitee.wsl.func.taggable


interface Taggable<Self : Taggable<Self>> {

    val tags: Map<String, Any>

    @Suppress("UNCHECKED_CAST")
    fun <T : Any> getTag(name: String): T? = tags[name] as T?

    fun replaceTags(tags: Map<String, Any>): Self

    fun containsTag(name: String): Boolean = name in tags

    fun containsAny(checkTags: Collection<String>): Boolean {
        for (checkTag in checkTags) {
            if (containsTag(checkTag)) return true
        }
        return false
    }

    companion object
}

fun <T : U, U : Taggable<U>, X : Any> T.addTag(
    name: String,
    value: X,
): T = addTags(name to value)

fun <T : U, U : Taggable<U>, X : Any> T.addTags(
    tag: Pair<String, X>,
    vararg otherTags: Pair<String, X>,
): T = this.addTags(mapOf(tag, *otherTags))

operator fun <T : U, U : Taggable<U>, X : Any> T.plus(tag: Pair<String, X>): T = addTags(tag)

fun <T : U, U : Taggable<U>, X : Any> T.addTags(tags: Map<String, X>): T = setTags(this.tags + tags)

operator fun <T : U, U : Taggable<U>, X : Any> T.plus(tags: Map<String, X>): T = addTags(tags)

fun <T : U, U : Taggable<U>, X : Any> T.setTags(tags: Map<String, X>): T = replaceTags(tags) as T

fun <T : U, U : Taggable<U>, X : Any> T.setTags(
    tag: Pair<String, X>,
    vararg otherTags: Pair<String, X>,
): T = setTags(mapOf(tag, *otherTags))

fun <T : U, U : Taggable<U>, X : Any> T.setTag(
    key: String,
    value: X,
): T = setTags(tags.toMutableMap().also { it[key] = value })

fun <T : U, U : Taggable<U>> T.clearTags(): T = setTags(emptyMap())

fun <T : U, U : Taggable<U>> T.retainAll(checkTags: List<String>?): Boolean {
    if(checkTags == null) {
        if (tags.isEmpty()) return false
        clearTags()
        return true
    }

    setTags(tags.filterKeys { it in checkTags })
    return tags.isNotEmpty()
}

